let getGrowingArray = (start, end, step) => {
    if (Math.abs(start) > 1 || Math.abs(end) > 1 || Math.abs(step) > 1) {
        return [0, 1];
    }
    else {
        let result = [];
        for (let i = start; i <= end; i += step) {
            result.push(i);
        }
        return result;
    }
}
let getValidRangeValue = (value, min, max) => {
    if (value < min) {
        return min;
    }
    else if (value > max) {
        return max;
    }
    else {
        return value;
    }
}

let deltaScrollTop = 0;
let scrollDirection = "down";
window.addEventListener("scroll", function (e) {
    scrollDirection = e.target.documentElement.scrollTop - deltaScrollTop > 0 ? "down" : "up";
    deltaScrollTop = e.target.documentElement.scrollTop;
    //console.log(e.target.documentElement.scrollTop, deltaScrollTop, scrollDirection)
}, true);

let opacityChange = (entry, element = 'self', options = {
    enhance: true,
    opacityOffset: 0
}) => {
    let target = element === 'self' ? entry.target : element;
    let ratio = 0;
    if (options.enhance) {
        ratio = options.opacityOffset ? parseFloat(entry.intersectionRatio.toPrecision(2)) + parseFloat(options.opacityOffset) : entry.intersectionRatio.toPrecision(2);
    }
    else {
        ratio = options.opacityOffset ? 1 - parseFloat(entry.intersectionRatio.toPrecision(2)) + parseFloat(options.opacityOffset) : 1 - entry.intersectionRatio.toPrecision(2);
    }
    ratio = getValidRangeValue(ratio, 0, 1);
    target.style.opacity = ratio;
}

let greyChange = (entry, element = 'self', options = {
    greyOffset: 0
}) => {
    let target = element === 'self' ? entry.target : element;
    let ratio = options.greyOffset ? 100 - parseInt(entry.intersectionRatio * 100) + parseInt(options.greyOffset) : 100 - parseInt(entry.intersectionRatio * 100);
    ratio = getValidRangeValue(ratio, 0, 100);
    target.style.filter = `grayscale(${ratio}%)`;
}

let widthChange = (entry, element = 'self', originWidth, options = {
    smaller: false,
    widthOffset: 0
}) => {
    let target = element === 'self' ? entry.target : element;
    let ratio = 0;
    if (options.smaller) {
        ratio = options.widthOffset ? 1 - parseFloat(entry.intersectionRatio) + parseFloat(options.widthOffset) : 1 - parseFloat(entry.intersectionRatio);
    }
    else {
        ratio = options.widthOffset ? parseFloat(entry.intersectionRatio) + parseFloat(options.widthOffset) : parseFloat(entry.intersectionRatio);
    }
    ratio = getValidRangeValue(ratio, 0, 1);
    target.style.width = `${ratio * originWidth}px`;
}

let videoChange = (entry) => {
    if (entry.intersectionRatio < 0.1) {
        entry.target.pause();
        entry.target.currentTime = 0;
    }
    if (entry.intersectionRatio > 0.9) {
        entry.target.play();
    }
}

let transformChange = (entry, element = 'self', options = {
    translateBegin: [0, 0, 0],
    translateEnd: [100, 100, 100],
    translateEnable: [true, true, true],
    scaleBegin: [0, 0, 0],
    scaleEnd: [100, 100, 100],
    scaleEnable: [true, true, true]
}) => {
    let target = element === 'self' ? entry.target : element;
    target.style.transform = "";
    if (options.translateEnable && options.translateEnable.indexOf(true) != -1) {
        let x = options.translateEnable[0] ? parseFloat(entry.intersectionRatio) * (options.translateEnd[0] - options.translateBegin[0]) + options.translateBegin[0] : options.translateBegin[0];
        let y = options.translateEnable[1] ? parseFloat(entry.intersectionRatio) * (options.translateEnd[1] - options.translateBegin[1]) + options.translateBegin[1] : options.translateBegin[1];
        let z = options.translateEnable[2] ? parseFloat(entry.intersectionRatio) * (options.translateEnd[2] - options.translateBegin[2]) + options.translateBegin[2] : options.translateBegin[2];
        x = getValidRangeValue(x, options.translateBegin[0], options.translateEnd[0]);
        y = getValidRangeValue(y, options.translateBegin[1], options.translateEnd[1]);
        z = getValidRangeValue(z, options.translateBegin[2], options.translateEnd[2]);
        target.style.transform += ` translate3d(${x}px,${y}px,${z}px)`;
    }
    if (options.scaleEnable && options.scaleEnable.indexOf(true) != -1) {
        let sx = options.scaleEnable[0] ? parseFloat(entry.intersectionRatio) * (options.scaleEnd[0] - options.scaleBegin[0]) + options.scaleBegin[0] : options.scaleBegin[0];
        let sy = options.scaleEnable[1] ? parseFloat(entry.intersectionRatio) * (options.scaleEnd[1] - options.scaleBegin[1]) + options.scaleBegin[1] : options.scaleBegin[1];
        let sz = options.scaleEnable[2] ? parseFloat(entry.intersectionRatio) * (options.scaleEnd[2] - options.scaleBegin[2]) + options.scaleBegin[2] : options.scaleBegin[2];
        sx = getValidRangeValue(sx, options.scaleBegin[0] >= 0 ? options.scaleBegin[0] : 0, options.scaleEnd[0]);
        sy = getValidRangeValue(sy, options.scaleBegin[1] >= 0 ? options.scaleBegin[1] : 0, options.scaleEnd[1]);
        sz = getValidRangeValue(sz, options.scaleBegin[2] >= 0 ? options.scaleBegin[2] : 0, options.scaleEnd[2]);
        target.style.transform += ` scale3d(${sx},${sy},${sz})`;
    }
}

let classChange = (entry, element = 'self', activateClassList = [{
    range: [0.1, 0.9],
    className: "myClass"
}]) => {
    let target = element === 'self' ? entry.target : element;
    if (activateClassList.length > 0) {
        activateClassList.map((value) => {
            if (value.className && value.range && value.range.length === 2 && value.range[0] <= value.range[1]) {
                if (entry.intersectionRatio >= value.range[0] && entry.intersectionRatio <= value.range[1]) {
                    target.classList.add(value.className);
                }
                else {
                    target.classList.remove(value.className);
                }
            }
        });
    }
}

let applyCommonEffect = (effectTargets = [], parentObserve = true, observerOptions = {
    root: document,
    rootMargin: `clientHeight`,
    threshold: getGrowingArray(0, 1, 0.01)
}, useDefined = true, callback = (...args) => {
    console.log(`empty callback:${args}`);
}, ...args) => {
    effectTargets = [...effectTargets];
    effectTargets.map((effectTarget) => {
        let observerTarget = parentObserve ? effectTarget.parentNode : effectTarget;
        const io = new IntersectionObserver(entries => {
            //console.log(entries, entries[0].intersectionRatio);
            if(useDefined){
                callback(entries[0], effectTarget, ...args);
            }
            else{
                callback(...args);
            }
        }, {
            root: observerOptions.root,
            rootMargin: observerOptions.rootMargin == `clientHeight` ? `${observerTarget.clientHeight}px 0px 0px 0px` : `0px 0px 0px 0px`,
            threshold: observerOptions.threshold
        })
        io.observe(observerTarget);
    });
}